#!/bin/bash

FILE_FSTAB="/etc/fstab"
FILE_MOUNTS="/proc/mounts"
FILE_PARTITIONS="/proc/partitions"
FILE_BASHRC="/etc/bash.bashrc"
FILE_VIMRC="/etc/vim/vimrc"
FILE_GROUP="/etc/group"
FILE_PASSWD="/etc/passwd"
FILE_EXPORTS="/etc/exports"
FILE_SAMBA_CONFIG="/etc/samba/smb.conf"
FILE_CAVAN_SERVICE="/etc/init.d/cavan"
FILE_CAVAN_SERVICE_CONF="/etc/init/cavan.conf"
FILE_GIT_DAEMON_CONF="/etc/init/git-daemon.conf"
FILE_GIT_DAEMON_RUN="/etc/sv/git-daemon/run"
FILE_GRUB_LINUX="/etc/grub.d/10_linux"
FILE_GRUB_CAVAN="/etc/grub.d/80_cavan"
FILE_APP_FEILED="/tmp/cavan-app-failed.txt"
DIR_SYSTEMD_CONFIG="/etc/systemd/system/multi-user.target.wants"
DIR_SOURCES_LIST="/etc/apt/sources.list.d"

CAVAN_HOME="/cavan"
SCRIPT_PATH="${CAVAN_HOME}/script"
SCRIPT_CAVAN_GRUB="${CAVAN_HOME}/config/80_cavan_grub"
SCRIPT_CAVAN_GRUB_PY="${CAVAN_HOME}/script/python/cavan_grub.py"

CPAN_PATH="/mnt/sda1"
DPAN_PATH="/mnt/sda5"
EPAN_PATH="/mnt/sda6"
FPAN_PATH="/mnt/sda7"
GPAN_PATH="/mnt/sda8"
UBUNTU_PATH="${DPAN_PATH}/ubuntu"
UBUNTU_HOME="${UBUNTU_PATH}/home"
FILE_SWAP_IMG="/var/swap.img"
FILE_VIMRC_VIM="${SCRIPT_PATH}/vim/vimrc.vim"

CAVAN_OUT_DEBUG="${CAVAN_HOME}/out/host/debug"
CMD_TCP_DD_SERVER="${CAVAN_OUT_DEBUG}/cavan-tcp_dd_server"
CMD_TFTP_DD_SERVER="${CAVAN_OUT_DEBUG}/cavan-tftp_dd_server"
CMD_TCP_PROXY="${CAVAN_OUT_DEBUG}/cavan-tcp_proxy"
CMD_CAVAN_SERVICE="${CAVAN_OUT_DEBUG}/cavan-service --start -s 0 --exec"

NFS_COMMON_CONFIG="sync,no_subtree_check,insecure,nohide"
NFS_RW_CONFIG="*(rw,${NFS_COMMON_CONFIG})"
NFS_RO_CONFIG="*(ro,${NFS_COMMON_CONFIG})"

function file_abs_directory()
{
	cd $(dirname $1) && pwd
}

if [ "$0" = "bash" ]
then
CMD_ABS_DIR="${SCRIPT_PATH}"
else
CMD_ABS_DIR="$(file_abs_directory $0)"
fi

CMD_ABS_PATH="${CMD_ABS_DIR}/$(basename $0)"
CORE_PATH="${CMD_ABS_DIR}/core"
FILE_APP_CONFIG="${CORE_PATH}/applications.cfg"
LOCAL_CAVAN_ROOT="$(dirname ${CMD_ABS_DIR})"
LOCAL_CONFIG_PATH="${LOCAL_CAVAN_ROOT}/config"

source "/etc/lsb-release"
source "${CORE_PATH}/file.sh"
source "${CORE_PATH}/device.sh"
source "${CORE_PATH}/stdio.sh"
source "${CORE_PATH}/alias.sh"

LOCAL_UBUNTU="${UBUNTU_PATH}/${DISTRIB_RELEASE}"

function get_user_config()
{
	awk -F ':' '$6 ~ /^\/(home|root)/ { print "username="$1, "homepath="$6 }' "${FILE_PASSWD}"
}

function get_user_list()
{
	local username homepath

	get_user_config | while read line
	do
		eval "$line"
		[ -d "${homepath}" ] && echo "${username}"
	done
}

unset USER_LIST USER_HAS_CAVAN

for username in $(get_user_list)
do
	[ "${username}" = "cavan" ] && USER_HAS_CAVAN="true"

	if [ "${USER_LIST}" ]
	then
		USER_LIST+=" ${username}"
	else
		USER_LIST="${username}"
	fi
done

echo "USER_LIST = ${USER_LIST}"
echo "USER_HAS_CAVAN = ${USER_HAS_CAVAN}"

function mount_disk()
{
	local mount_dev mount_point disk line

	if [ "$1" ]
	then
		disk="$1"
	else
		disk="sda"
	fi

	while read line
	do
		echo ${line} | grep "${disk}[0-9]\+" || continue
		set ${line}
		[ "$3" -gt "10" ] || continue

		mount_point="/mnt/$4"
		mount_dev="/dev/$4"

		[ $(grep "^\s*${mount_dev}\b" "${FILE_MOUNTS}" "${FILE_FSTAB}" | wc -l) -lt 2 ] || continue

		echo "${mount_dev} => ${mount_point}"

		umount_directory "${mount_point}"
		mkdir -pv "${mount_point}"
		umount "${mount_dev}"
		mount "${mount_dev}" "${mount_point}" ||
		{
			rmdir "${mount_point}"
			continue
		}

		grep "^\s*${mount_dev}\b" "${FILE_FSTAB}" ||
		{
			echo "/dev/$4 ${mount_point} auto errors=remount-ro 0 0" >> ${FILE_FSTAB}
		}
	done < ${FILE_PARTITIONS}
}

function swap_init()
{
	cat /proc/swaps | grep partition && return 0

	[ -f "${FILE_SWAP_IMG}" ] ||
	{
		dd if=/dev/zero of=${FILE_SWAP_IMG} bs=4M count=1024 || return 1
		mkswap -L CFA8888 ${FILE_SWAP_IMG} || return 1
	}

	swapon ${FILE_SWAP_IMG} || return 1
	cat ${FILE_FSTAB} | grep "${FILE_SWAP_IMG}" && return 0
	echo "${FILE_SWAP_IMG} swap swap default 0 0" >> ${FILE_FSTAB}
}

function create_mount_points()
{
	mkdir /mnt -pv
	cd /mnt || return 1

	for index in $(seq 1 9)
	do
		mkdir upan${index} -pv
		mkdir img${index} -pv
		mkdir net${index} -pv
	done
}

function create_symlinks()
{
	[ "${USER_HAS_CAVAN}" = "true" ] || return 0

	cavan-symlink ${CPAN_PATH} /cpan || return 1
	cavan-symlink ${DPAN_PATH} /dpan || return 1
	cavan-symlink ${EPAN_PATH} /epan || return 1
	cavan-symlink ${EPAN_PATH}/source /source || return 1
	cavan-symlink ${FPAN_PATH} /fpan || return 1
	cavan-symlink ${GPAN_PATH} /gpan || return 1
	cavan-symlink ${UBUNTU_PATH} /ubuntu || return 1

	for dir in cavan work git svn book project tools app temp logs
	do
		cavan-symlink ${UBUNTU_PATH}/${dir} /${dir} || return 1
	done
}

function config_bashrc()
{
	local bashrc username found

	for username in ${USER_LIST}
	do
		bashrc="/home/${username}/.bashrc"

		[ -f "${bashrc}" ] &&
		{
			cp -av "${bashrc}" "${FILE_BASHRC}" || return 1
			mv -v "${bashrc}" "${bashrc}.bak"
			found="true"
		}
	done

	[ "${found}" = "true" ] || return 0

	mv -v /root/.bashrc /root/.bashrc.bak

	sed -i ${FILE_BASHRC} \
		-e 's,^\s*#\s*\(force_color_prompt=yes\),\1,g'

	cat >> ${FILE_BASHRC} << EOF

# Following is Cavan's configs
CAVAN_HOME="/cavan"
TOOLS_HOME="/tools"
SSH_USER="${SSH_USER-jwaoo}"
SMB_SERVER_IP="${SMB_SERVER_IP-192.168.1.250}"
SMB_USER="${SMB_USER-jwaoo}"
SMB_PASSWORD="${SMB_PASSWORD-server}"
SMB_ENTRY="${SMB_ENTRY-work}"
CAVAN_SERVER_IP="\${CAVAN_SERVER_IP-192.168.1.250}"
CAVAN_SERVER_PORT="\${CAVAN_SERVER_PORT-8888}"
PROJECT_HOME="${PROJECT_HOME}"
PRODUCT_HOME="${PRODUCT_HOME-/project/product}"
REMOTE_PROJECT_HOME="${REMOTE_PROJECT_HOME-\${SSH_USER}}"
REMOTE_PRODUCT_HOME="${REMOTE_PRODUCT_HOME-/home/\${SSH_USER}/product}"

source ${SCRIPT_PATH}/core/bashrc.sh
EOF
}

function config_vimrc()
{
	cat >> ${FILE_VIMRC} << EOF

" Following is Cavan's configs
if filereadable("${FILE_VIMRC_VIM}")
  source ${FILE_VIMRC_VIM}
endif
EOF
}

function config_group()
{
	local userlist

	userlist=$(echo ${USER_LIST} | sed 's/\s\+/,/g')

	sed -i "s/:\s*$/:${userlist}/g" ${FILE_GROUP}
}

function config_nfs()
{
	[ "${USER_HAS_CAVAN}" = "true" ] || return 0

	for exp in /
	do
		echo -e "${exp}\t\t\t${NFS_RO_CONFIG}"
	done >> ${FILE_EXPORTS}

	for exp in /tmp /temp /cavan /git /ubuntu /book /cpan /dpan /epan /fpan /gpan
	do
		echo -e "${exp}\t\t${NFS_RW_CONFIG}"
	done >> ${FILE_EXPORTS}

	service nfs-kernel-server restart
}

function config_samba()
{
	cat >> ${FILE_SAMBA_CONFIG} << EOF
[global]
   follow symlinks = true
   wide links = true
   unix extensions = no

[rootfs]
   comment = ${DISTRIB_ID}-${DISTRIB_RELEASE}
   browseable = yes
   path = /
   guest ok = yes
   read only = no
   create mask = 0777
   dos charset = cp936
   unix charset = gb2312
EOF

	service smbd restart

	return 0
}

function config_single_home()
{
	[ "${USER_HAS_CAVAN}" = "true" ] || return 0

	cd $1 || return 1

	for dir in Desktop Documents Downloads Music Pictures .stardict .gradle .VirtualBox "VirtualBox VMs"
	do
		cavan-symlink "${UBUNTU_HOME}/${dir}" "${dir}" || return 1
	done

	cavan-symlink "${CAVAN_HOME}" "cavan" || return 1
	cavan-symlink "${SCRIPT_PATH}/configs/netrc" ".netrc" || return 1
}

function config_home()
{
	[ "${USER_HAS_CAVAN}" = "true" ] || return 0

	for home in /root /home/*
	do
		config_single_home ${home} || return 1
	done
}

function config_aptget()
{
	local var_path etc_path

	[ "${USER_HAS_CAVAN}" = "true" ] || return 0

	var_path="${LOCAL_UBUNTU}/var"
	etc_path="${LOCAL_UBUNTU}/etc"

	cavan-symlink ${etc_path}/apt /etc/apt || return 1
	cavan-symlink ${var_path}/cache/apt /var/cache/apt || return 1

	mkdir -pv "${DIR_SOURCES_LIST}" || return 1
	echo "deb http://download.virtualbox.org/virtualbox/debian ${DISTRIB_CODENAME} contrib" > "${DIR_SOURCES_LIST}/virtualbox.list"
	# echo "deb http://archive.ubuntukylin.com:10006/ubuntukylin trusty main" > "${DIR_SOURCES_LIST}/sogoupinyin.list"
	# echo "deb http://ftp.de.debian.org/debian wheezy main" > "${DIR_SOURCES_LIST}/debian.list"

	wget -q https://www.virtualbox.org/download/oracle_vbox.asc -O- | apt-key add -
}

function config_git()
{
	local file_gitconfig username homepath
	local GIT_EXEC_PATH="$(git --exec-path)"
	local CMD_GIT_DAEMON="${GIT_EXEC_PATH}/git-daemon --verbose --export-all --enable=receive-pack --enable=upload-pack --enable=upload-archive --base-path=/git"

	cavan-git-config || return 1

	file_gitconfig="${HOME}/.gitconfig"
	echo "file_gitconfig = ${file_gitconfig}"

	get_user_config | while read line
	do
		eval ${line}

		[ -d "${homepath}" ] || continue
		[ "${homepath}" = "${HOME}" ] && continue

		cp -av "${file_gitconfig}" "${homepath}" || return 1
		chown -v "${username}:${username}" "${homepath}/.gitconfig" || return 1
	done

	if [ -e "${FILE_GIT_DAEMON_RUN}" ]
	then
		cat > ${FILE_GIT_DAEMON_RUN} << EOF
#!/bin/sh

exec 2>&1
echo 'git-daemon starting.'
exec chpst -ugitdaemon ${CMD_GIT_DAEMON}
EOF
	else
		cat > ${FILE_GIT_DAEMON_CONF} << EOF
description "git daemon"

start on runlevel [2345] or net-device-up

exec ${CMD_CAVAN_SERVICE} "${CMD_GIT_DAEMON}"
EOF

		chmod 0644 ${FILE_GIT_DAEMON_CONF} || return 1
	fi
}

function install_applications()
{
	apt-get clean || return 1
	rm -rf /var/lib/apt/lists/*
	rm -rf /var/lib/apt/lists/partial/*
	apt-get clean || return 1
	dpkg --configure -a || return 1
	apt-get update --fix-missing # || return 1
	apt-get install -fy --force-yes --show-progress $(cat "${FILE_APP_CONFIG}" | sed 's/#.*$//g') ||
	{
		rm -rf "${FILE_APP_FEILED}" || return 1

		cat "${FILE_APP_CONFIG}" | while read line
		do
			[[ $line = \#* ]] && continue

			echo "Install application: $line"
			apt-get install -fy --force-yes $line && continue

			echo "$line" >> "${FILE_APP_FEILED}"
		done

		[ -f "${FILE_APP_FEILED}" ] &&
		{
			echo "Failed to install application:"
			cat "${FILE_APP_FEILED}"
			return 1
		}
	}

	apt-get autoremove -fy --force-yes --show-progress || return 1
}

function install_debin_packages()
{
	for pkg in ${LOCAL_UBUNTU}/debs/*.deb ${UBUNTU_PATH}/debs/*.deb
	do
		[ -f "${pkg}" ] || continue
		pr_title "Install debin package ${pkg}"
		dpkg -i ${pkg} || return 1
	done
}

function config_stardict()
{
	cd /usr/share/stardict/dic || return 1

	for dic in ${UBUNTU_PATH}/app/stardict/*.tar.*
	do
		[ -f "${dic}" ] || continue
		pr_title "Install stardict ${dic}"
		tar -xf ${dic} || return 1
	done
}

function config_service()
{
	cat > ${FILE_CAVAN_SERVICE} << EOF
#!/bin/sh

[ "\$(id -u)" = "0" ] ||
{
	echo "Only super user can do this"
	exit 1
}

CMD_START_STOP_DAEMON="start-stop-daemon --quiet --oknodo"
CAVAN_SERVER_LIST="${CMD_TCP_DD_SERVER} ${CMD_TFTP_DD_SERVER}"
CAVAN_SERVER_OPTION="--daemon"

case "\$1" in
	start)
		for cmd in \${CAVAN_SERVER_LIST}
		do
			\${CMD_START_STOP_DAEMON} --start --exec \${cmd} -- \${CAVAN_SERVER_OPTION}
		done
		;;
	stop)
		for cmd in \${CAVAN_SERVER_LIST}
		do
			\${CMD_START_STOP_DAEMON} --stop --exec \${cmd}
		done
		;;
	restart)
		for cmd in \${CAVAN_SERVER_LIST}
		do
			\${CMD_START_STOP_DAEMON} --stop --exec \${cmd}
		done

		for cmd in \${CAVAN_SERVER_LIST}
		do
			\${CMD_START_STOP_DAEMON} --start --exec \${cmd} -- \${CAVAN_SERVER_OPTION}
		done
		;;
esac
EOF

	chmod 0555 ${FILE_CAVAN_SERVICE} || return 1

cat > ${FILE_CAVAN_SERVICE_CONF} << EOF
description "cavan daemon"

start on runlevel [2345] or net-device-up

exec ${CMD_TCP_DD_SERVER} -d & ${CMD_TCP_PROXY} -adp 9999 --pp 8888 & ${CMD_TCP_PROXY} -adp 9090 --pp 9090 & ${CMD_TCP_PROXY} -dp 8080 -i 10.1.1.153 --pp 9090
EOF

	chmod 0644 ${FILE_CAVAN_SERVICE_CONF} || return 1

	return 0
}

function config_grub()
{
	sed 	-e 's#^\(\s*linux.*\s\+root=\).*$#\1${GRUB_DEVICE} vga=0x318#g' \
			-e 's/^\s*printf.*\${prepare_\w*_cache}/# &/g' \
			-i ${FILE_GRUB_LINUX} || return 1

	cat > "${FILE_GRUB_CAVAN}" << EOF
#!/bin/sh

if [ -f "${SCRIPT_CAVAN_GRUB_PY}" ]
then
	python "${SCRIPT_CAVAN_GRUB_PY}"
elif [ -f "${SCRIPT_CAVAN_GRUB}" ]
then
	bash "${SCRIPT_CAVAN_GRUB}"
fi
EOF

	chmod a+x "${FILE_GRUB_CAVAN}" || return 1
	update-grub2 || return 1

	return 0
}

function config_gitweb()
{
	cd /etc/apache2/mods-enabled || return 1
	ln -vsf ../mods-available/{cgid.*,ssl.*,*shmcb*,dav*} . || return 1
	cd /etc/apache2/sites-enabled || return 1
	ln -vsf ../sites-available/* . || return 1
	sed -i 's/^\s*\(\$projectroot\)\s*=.*$/\1 = "\/git";/g' /etc/gitweb.conf || return 1
	cp -av ${LOCAL_CONFIG_PATH}/gitweb/* /usr/share/gitweb/static || return 1
	ln -vsf ${CAVAN_HOME}/config/git/git.conf /etc/apache2/conf-enabled/ || return 1

	service apache2 restart

	return 0
}

function config_systemd()
{
	local target_path

	cd "${LOCAL_CONFIG_PATH}/systemd" || return 1

	for fn in *.service
	do
		target_path="${DIR_SYSTEMD_CONFIG}/$fn"
		rm "${target_path}"
		cp -av "$fn" "${target_path}" || return 1
		chmod -v 0644 "${target_path}" || return 1
	done

	systemctl daemon-reload

	return 0
}

function config_others()
{
	ln -sf /tools/eclipse /usr/bin || return 1

	return 0
}

function config_sudo()
{
	local dest_path="/etc/sudoers.d/cavan-sudoers"
	cp -av "${LOCAL_CONFIG_PATH}/sudoers" "${dest_path}"
	chmod -v a-w "${dest_path}"
	chown -v root:root "${dest_path}"
}

pr_title "${DISTRIB_ID}-${DISTRIB_RELEASE} (${DISTRIB_CODENAME})"

[ "$(id -u)" = "0" ] ||
{
	pr_red_info "Only root user can run ${CMD_ABS_PATH}"

	exit 1
}

[ "$0" = "bash" ] || for func in mount_disk create_mount_points create_symlinks config_bashrc \
	swap_init config_aptget install_applications install_debin_packages \
	config_nfs config_samba config_home config_git config_vimrc config_group config_sudo \
	config_service config_grub config_stardict config_gitweb config_systemd config_others
do
	if cavan-has_mark ${func}
	then
		pr_green_info "${func} is already completed"
	else
		pr_title "Start ${func}"
		if ${func}
		then
			cavan-create_mark ${func}
			pr_green_info "${func} successfull"
		else
			pr_red_info "${func} failed"
			exit 1
		fi
	fi
done
